/*
Kakine
ActionScript Framework
Copyright © 2011, PUNY, LLC.

This file is part of KAKINE.

KAKINE is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

KAKINE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with KAKINE.  If not, see <http://www.gnu.org/licenses/>.
*/ 
package com.puny.utils
{
	import flash.events.Event;
	import flash.geom.Rectangle;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;
	
	/**
	 * 
	 * @author puny
	 * 
	 */
	public class SwfParser extends URLLoader
	{
		private static const ZLIB:String = "zlib";
		private static const COMPRESSED:String = "C";
		private static const TYPE:String = "type";
		private static const LENGTH:String = "length";
		private static const TAG_END:String = "0";
		private var _signature1:String;
		private var _signature2:String;
		private var _signature3:String;
		private var _version:uint;
		private var _fileLength:Number;
		private var _frameSize:Rectangle;
		private var _frameReate:uint;
		private var _frameCount:uint;
		private var _swfSize:RectParser;
		protected var _swf:ByteArray;
		/**
		 *  
		 * @param request path for a swf path
		 * 
		 */
		public function SwfParser(request:URLRequest=null)
		{
			super();
			dataFormat = URLLoaderDataFormat.BINARY;
			addEventListener(Event.COMPLETE, completedHandler);
			load(request);
		}
		
		private function completedHandler(event:Event):void {
			_swf = this.data as ByteArray;

//			dump();
			
			readHeader();
			var ret:Boolean = true;
			while(ret) {
				ret = readRecord();
			}
		}
		
		private function dump():void {
			var line:String = "";
			var b:String;
			while(_swf.position < _swf.length) {
				b = _swf.readUnsignedByte().toString(16).toLocaleUpperCase();
				if (b.length == 1) {
					line += "0";
				}
				line += b + " ";
				if (line.length == 24) {
					line+= " ";
				} else if (line.length == 49) {
					trace(line);
					line = "";
				}
			}
		}
		
		private function readHeader():void {
			_signature1 = String.fromCharCode( _swf.readUnsignedByte());
			_signature2 = String.fromCharCode( _swf.readUnsignedByte());
			_signature3 = String.fromCharCode( _swf.readUnsignedByte());
			_version = readUI(8);
			_fileLength = readUI(32);
			var compressed:ByteArray = new ByteArray();
			_swf.readBytes(compressed, 0, _swf.length-8);
			if (_signature1 == COMPRESSED ) {
				compressed.uncompress();
			}
			_swf = compressed;
			_swfSize = new RectParser(_swf);

			var rate:Number = readUI(8)/1000 + readUI(8);
			var frameCount:uint = readUI(16);
		}
		
		private function readRecord():Boolean {
			var recordHeader:Object = readRecordHeader();
			trace(recordHeader[TYPE], recordHeader[LENGTH]);
			if (!parseTag(recordHeader[TYPE])) {
				//Skip
				var line:String = "Skip:";
				var byte:String;
				for(var i:int = 0;i < recordHeader[LENGTH];i++) {
					byte = readUI(8).toString(16).toUpperCase();
					if (byte.length == 1) {
						byte = "0"+byte;
					}
					line += byte + " ";
				}
				trace(line);
			}
			return _swf.position < _swf.length;
		}
		
		protected function parseTag(type:String):Boolean {
			return false;
		}
		
		private function readRecordHeader():Object  {
			var obj:Object = new Object();
			var fb:uint = _swf.readUnsignedByte();
			var sb:uint = _swf.readUnsignedByte();
			obj[TYPE] = sb * 4 + (fb >> 6);
			var length:uint = fb & 0x3F;
			if (length == 0x3F) {
				fb = _swf.readUnsignedByte();
				sb = _swf.readUnsignedByte();
				var tb:uint = _swf.readUnsignedByte();
				var lb:uint = _swf.readUnsignedByte();
				length = (lb & 0x7F)*0x1000000 + tb * 0x10000 + sb * 0x100 + fb;
			}
			obj[LENGTH] = length;
			return obj;
		}
				
		protected function readUI(byte:uint):uint {
			var num:uint = byte / 8;
			var ret:uint = 0;
			for(var i:int = 0;i < num;i++) {
				ret += _swf.readUnsignedByte() * Math.pow(0x100, i);
			}
			return ret;
		}
	}
}